package com.tjx.utils;

import com.tjx.entity.Coupon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Component
public class RedisUtils {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // ============================ String 类型操作 ============================

    /**
     * 设置缓存（无过期时间）
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置缓存（带过期时间）
     */
    public void set(String key, Object value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 获取缓存
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 原子递增（默认+1）
     * @param key 键
     * @return 递增后的值
     */
    public Long increment(String key) {
        return redisTemplate.opsForValue().increment(key);
    }

    /**
     * 原子递增（自定义步长）
     * @param key 键
     * @param delta 步长（正数递增，负数递减）
     * @return 递增后的值
     */
    public Long increment(String key, long delta) {
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 删除缓存
     */
    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 判断 key 是否存在
     */
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 设置过期时间
     * @param key 键
     * @param timeout 过期时间
     * @param unit 时间单位
     * @return 是否设置成功
     */
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }


    // ============================ Hash 类型操作 ============================

    /**
     * 向 Hash 中添加单个键值对
     * @param key 主键
     * @param hashKey Hash中的子键
     * @param value 值
     */
    public void hset(String key, String hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 向 Hash 中批量添加键值对
     * @param key 主键
     * @param map 键值对集合
     */
    public void hsetAll(String key, Map<String, Object> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 获取 Hash 中单个子键的值
     * @param key 主键
     * @param hashKey Hash中的子键
     * @return 对应的值
     */
    public Object hget(String key, String hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 获取 Hash 中所有键值对
     * @param key 主键
     * @return 所有键值对（Map）
     */
    public Map<Object, Object> hgetAll(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取 Hash 中所有子键
     * @param key 主键
     * @return 子键集合
     */
    public Set<Object> hkeys(String key) {
        return redisTemplate.opsForHash().keys(key);
    }

    /**
     * 获取 Hash 中所有值
     * @param key 主键
     * @return 值集合
     */
    public List<Object> hvals(String key) {
        return redisTemplate.opsForHash().values(key);
    }

    /**
     * 删除 Hash 中的单个或多个子键
     * @param key 主键
     * @param hashKeys 子键数组
     * @return 删除的数量
     */
    public Long hdelete(String key, Object... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * 判断 Hash 中是否存在某个子键
     * @param key 主键
     * @param hashKey 子键
     * @return 是否存在
     */
    public Boolean hhasKey(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * Hash 中子键值原子递增（可用于计数）
     * @param key 主键
     * @param hashKey 子键
     * @param delta 步长（正数递增，负数递减）
     * @return 递增后的值
     */
    public Long hincrement(String key, String hashKey, long delta) {
        return redisTemplate.opsForHash().increment(key, hashKey, delta);
    }


    // ============================ List 类型操作 ============================

    /**
     * 向 List 左侧（头部）添加元素
     * @param key 键
     * @param value 元素
     * @return 列表长度
     */
    public Long lleftPush(String key, Object value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 向 List 左侧（头部）批量添加元素
     * @param key 键
     * @param values 元素集合
     * @return 列表长度
     */
    public Long lleftPushAll(String key, Collection<Object> values) {
        return redisTemplate.opsForList().leftPushAll(key, values);
    }

    /**
     * 向 List 右侧（尾部）添加元素
     * @param key 键
     * @param value 元素
     * @return 列表长度
     */
    public Long lrightPush(String key, Object value) {
        return redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 向 List 右侧（尾部）批量添加元素
     * @param key 键
     * @param values 元素集合
     * @return 列表长度
     */
    public Long lrightPushAll(String key, Collection<Object> values) {
        return redisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * 获取 List 中指定范围的元素（从 start 到 end，包含两端）
     * @param key 键
     * @param start 起始索引（0 开始，-1 表示最后一个元素）
     * @param end 结束索引
     * @return 元素列表
     */
    public List<Object> lrange(String key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 获取 List 长度
     * @param key 键
     * @return 长度
     */
    public Long lsize(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 获取 List 中指定索引的元素
     * @param key 键
     * @param index 索引
     * @return 元素
     */
    public Object lindex(String key, long index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * 从 List 左侧（头部）弹出元素（移除并返回）
     * @param key 键
     * @return 弹出的元素
     */
    public Object lleftPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 从 List 右侧（尾部）弹出元素（移除并返回）
     * @param key 键
     * @return 弹出的元素
     */
    public Object lrightPop(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    /**
     * 移除 List 中指定数量的某个元素
     * @param key 键
     * @param count 移除数量（正数：从左到右；负数：从右到左；0：移除所有）
     * @param value 要移除的元素
     * @return 实际移除的数量
     */
    public Long lremove(String key, long count, Object value) {
        return redisTemplate.opsForList().remove(key, count, value);
    }


    // ============================ Set 类型操作 ============================

    /**
     * 向 Set 中添加单个元素
     * @param key 键
     * @param value 元素
     * @return 是否添加成功（已存在则返回 false）
     */
    public Boolean sadd(String key, Object value) {
        // redisTemplate.opsForSet().add(...) 底层调用Redis的SADD命令，返回添加成功的元素个数
        Long addCount = redisTemplate.opsForSet().add(key, value);
        // addCount=1 → 首次添加；addCount=0 → 已存在
        return addCount != null && addCount > 0;
    }

    /**
     * 向 Set 中批量添加元素
     * @param key 键
     * @param values 元素数组
     * @return 成功添加的数量（已存在的元素不计数）
     */
    public Long saddAll(String key, Object... values) {
        return redisTemplate.opsForSet().add(key, values);
    }

    /**
     * 获取 Set 中所有元素
     * @param key 键
     * @return 元素集合
     */
    public Set<Object> sall(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 判断元素是否在 Set 中
     * @param key 键
     * @param value 元素
     * @return 是否存在
     */
    public Boolean scontains(String key, Object value) {
        return redisTemplate.opsForSet().isMember(key, value);
    }

    /**
     * 获取 Set 的大小（元素数量）
     * @param key 键
     * @return 元素数量
     */
    public Long ssize(String key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 从 Set 中移除单个元素
     * @param key 键
     * @param value 元素
     * @return 是否移除成功
     */
    public Boolean sremove(String key, Object value) {
        return redisTemplate.opsForSet().remove(key, value) > 0;
    }

    /**
     * 从 Set 中批量移除元素
     * @param key 键
     * @param values 元素数组
     * @return 移除的数量
     */
    public Long sremoveAll(String key, Object... values) {
        return redisTemplate.opsForSet().remove(key, values);
    }

    /**
     * 随机从 Set 中弹出一个元素（移除并返回）
     * @param key 键
     * @return 弹出的元素
     */
    public Object spop(String key) {
        return redisTemplate.opsForSet().pop(key);
    }

    /**
     * 计算两个 Set 的交集（共同元素）
     * @param key1 第一个 Set 键
     * @param key2 第二个 Set 键
     * @return 交集元素集合
     */
    public Set<Object> sinter(String key1, String key2) {
        return redisTemplate.opsForSet().intersect(key1, key2);
    }

    /**
     * 计算两个 Set 的并集（所有元素，去重）
     * @param key1 第一个 Set 键
     * @param key2 第二个 Set 键
     * @return 并集元素集合
     */
    public Set<Object> sunion(String key1, String key2) {
        return redisTemplate.opsForSet().union(key1, key2);
    }


    // ============================ 工具方法 ============================

    /**
     * 将 Coupon 对象转为 Map（用于 Hash 存储）
     */
        public Map<String, Object> convertToMap(Object obj) throws IllegalAccessException {
        Map<String, Object> map = new HashMap<>();
        // 反射获取字段值（示例逻辑）
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Object value = field.get(obj);
            if (value instanceof LocalDate) {
                map.put(field.getName(), ((LocalDate) value).toString()); // 转为字符串
            } else {
                map.put(field.getName(), value);
            }
        }
        return map;
    }
}